// 对象类型

// 1.使用接口定义对象类型
interface Person {
  name: string;
  age: number;
}

function greet(person: Person) {
  return `Hello, ${person.name}! ${person.age} years old`;
}

// 2.使用类型别名type来定义对象类型
type Person2 = {
  name: string;
  age: number;
}

function greet2(person: Person2) {
  return `Hello, ${person.name}! ${person.age} years old`;
}

/**属性修饰符 */
// 1.可选属性
interface Shape {
  color: string;
}

declare function getShape(): Shape;

interface PaintPoints {
  shape: Shape;
  xPos?: number;
  yPos?: number;
}

function paintShape(opts: PaintPoints) {
  // ....
  let xPos = opts.xPos || 0
  let yPos = opts.yPos || 0
  console.log(xPos, yPos)
}

// 换一种写法：参数解构+默认赋值
function paintShape2({ shape, xPos = 0, yPos = 0 }:PaintPoints) {
  console.log(shape, xPos, yPos)
}

const shape = getShape()
paintShape({ shape })
paintShape({ shape, xPos: 100 })
paintShape({ shape, xPos: 100, yPos: 100 })


// 2. readonly 修饰符
interface SomeType {
  readonly thing: string
}

interface Home {
  readonly resident: { name: string; age: number }
}

function doSomething(opt: SomeType, home: Home) {
  // opt.thing = 'hello' // 报错，因为thing是只读属性
  // home.resident = { name: '123', age: 123 } // 报错，因为resident是只读属性
  home.resident.name = '123' // OK，resident引用不变
}

/** 索引签名 */
interface Animals {
  [index: number]: string;
}

declare function getStringArray(): Animals;

const myArray: Animals = getStringArray()
const item1 = myArray[1]


/** 溢出属性检测 */
interface SquareConfig {
  color?: string;
  width?: number;
  // [propName: string]: unknown; // 可以有任意数量的属性，只要它们不是 color 或 width，它们的类型并不重要
} 
function createSquare(config: SquareConfig): { color: string; area: number } {
  return {
    color: config.color || "red",
    area: config.width ? config.width * config.width : 20,
  };
}
 
// let mySquare = createSquare({ colour: "red", width: 100 }); //  错误，属性名是colour
let mySquare1 = createSquare({ width: 100, opacity: 0.5 } as SquareConfig); // 使用类型断言，绕过检查
console.log(mySquare1)

// 将对象分配给另一个变量：由于分配 squareOptions 不会进行溢出属性检查
let squareOptions = { colour: "red", width: 100 };
let mySquare2 = createSquare(squareOptions);

// 上述方式必须要具有共同属性，否则也会报错
let squareOptions2 = { colour: "red" };
// let mySquare3 = createSquare(squareOptions2); //报错，类型“{ colour: string; }”与类型“SquareConfig”不具有相同的属性

/** 扩展类型（extends） */
interface BasicAddress {
  name?: string;
  street: string;
  city: string;
  country: string;
  postalCode: string;
}
 
interface AddressWithUnit extends BasicAddress {
  unit: string;
}

// 多种类型扩展
interface Colorful {
  color: string;
}

interface Circle {
  radius: number;
}

interface ColorfulCircle extends Colorful, Circle {}
const cc: ColorfulCircle = {
  color: "red",
  radius: 42,
};

/** 交叉类型（&） */
type ColorfulCircle2 = Colorful & Circle;
const cc2: ColorfulCircle2 = { color: 'red', radius: 42}

function draw(circle: Colorful & Circle) {
  console.log(`Color was ${circle.color}`);
  console.log(`Radius was ${circle.radius}`);
}

draw({ color: "blue", radius: 42 });

export {}